﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IWMAG.Scripting.AST.ObjectModel;
using IWMAG.Scripting.AST.Declarations;
using IWMAG.Scripting.Interpreter;
using IWMAG.Scripting.Compiler.UserInfo;

namespace IWMAG.Scripting.AST.Statements {
    internal class BlockStatement : CodeStatement {
        public List<CodeStatement> Statements = new List<CodeStatement>();

        public BlockStatement(Compiler.Lexeme l) : base(l) {
        }

        public override bool Optimize()
        {
            if (EliminateDeadCode())
            {
                return true;
            }

            return false;
        }

        private bool EliminateDeadCode()
        {
            for (int i = 0; i < Statements.Count; i++)
            {
                if (Statements[i] is ReturnStatement || Statements[i] is ContinueStatement || Statements[i] is BreakStatement)
                {
                    var s = Statements.ToArray();
                    Statements = new List<CodeStatement>(s.TakeWhile(e => !(e is ReturnStatement || e is ContinueStatement || e is BreakStatement)));
                    return true;
                }
            }

            return false;
        }

        public override void Verify(Helpers.CompileTable sym, List<Compiler.IUserInfo> error) {
            sym.OpenScope();

            var allDuplicates = Statements.Where((a) => a is VariableDeclarationStatement).Select(
                (a) => (a as VariableDeclarationStatement).Declaration).GroupBy(
                (a) => a.Name).Where((a) => a.Count() > 1);
            if (allDuplicates.Count() > 0) {
                foreach (var duplicateSet in allDuplicates) {
                    foreach (var allExceptFirst in duplicateSet.Skip(1))
                    {
                        allExceptFirst.SendError(error, Rules.RedeclaredVariableInScope, allExceptFirst.Name);
                    }
                    
                }
            }

            var c = Statements.SkipWhile(e => !(e is ReturnStatement || e is ContinueStatement || e is BreakStatement)).Skip(1).Take(1);
            foreach (var item in c)
            {
                item.SendWarning(error, Rules.DeadCode_Warning);
            }

            foreach (CodeStatement stmnt in Statements) {
                stmnt.Verify(sym, error);
            }

            sym.CloseScope();
        }

        public override IEnumerable<Continuation> Execute(Interpreter.ScriptEngine engine, Helpers.RuntimeTable sym) {
            sym.OpenScope();
            foreach (CodeStatement statement in Statements) {
                foreach (Continuation wait in statement.Execute(engine, sym)) yield return wait;
            }
            sym.CloseScope();
        }
    }
}
